/*********************
*@file: file.go
*@author: junjunwang@wlrobo.com
*@brief:  文件操作接口
*@function: 实现对文件的创建、创建删除
*@version: 1.0
*@date: 2024/2/22 17:06
*********************/
package file

import (
	"WrStoreServer/config"
	"WrStoreServer/db"
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

const (
	diffTime = 3600 * 24 * 180 // 告警数据保存1800天
)

// 文件信息结构体
type FileInfo struct {
	Path    string
	ModTime time.Time
}

// 磁盘状态结构体
type DiskStat struct {
	Total uint64
	Free  uint64
	Used  uint64
	Usage float64
}
type RobotMsg struct {
	RobotSn  string `json:"robotSn"`
	DataType string `json:"dataType"` //数据类型(jpg、txt等)
	DateTime string `json:"dateTime"`
	Msg      string `json:"msg"`
}

var (
	source         string
	usageThreshold float64
	Ptv            config.Cfg
)

// 初始化获取资源路径
func init() {
	JsonParse := config.NewJsonStruct()
	Ptv = JsonParse.LoadCfg() //获取结构体信息
	source = Ptv.Dir + "/Source"
	usageThreshold = Ptv.UsageThreshold
	logrus.Info("usageThreshold :", usageThreshold)

}

// 文件操作
type FileHandler struct{}

func NewFileStruct() *FileHandler {
	return &FileHandler{}
}

// CreateDateDir 创建日期目录
func (fh *FileHandler) CreateDateDir(basePath string) (string, string) {
	folderName := time.Now().Format("20060102150405")
	folderPath := filepath.Join(basePath, folderName)
	if err := os.MkdirAll(folderPath, 0777); err != nil {
		logrus.Error("文件创建失败：", err)
		return "", ""
	}
	logrus.Info("文件创建成功 folderPath: ", folderPath, " folderName: ", folderName)
	return folderPath, folderName
}

func (fh *FileHandler) DelFileList(path string) error {
	nowTime := time.Now().Unix()
	err := filepath.Walk(path, func(path string, pfile os.FileInfo, err error) error {
		if pfile == nil {
			logrus.Error("没有获取到文件目录")
			return err
		}
		fileTime := pfile.ModTime().Unix()
		if (nowTime - fileTime) > diffTime { // 判断是否超过30天
			if err := os.RemoveAll(path); err != nil {
				logrus.Error("删除文件失败：", err)
			} else {
				logrus.Info("文件删除成功：", path)
			}
		} else {
			logrus.Info("剩余文件路径：", path)
		}
		return nil
	})
	if err != nil {
		logrus.Error("filepath.Walk()错误：", err)
		return err
	}
	return nil
}

// 检查是否为空目录
func (fh *FileHandler) isDirEmpty(path string) bool {
	f, err := os.Open(path)
	if err != nil {
		return false
	}
	defer f.Close()
	//ReadDir 读取目录的第一个条目，如果没有条目录为空
	_, err = f.Readdirnames(1)
	return err == io.EOF
}

// 解析文件路劲啊，提取消息名、日期时间、数据类型等
func (fh *FileHandler) parseDetail(path string) (*RobotMsg, error) {
	parts := strings.Split(path, "/")
	if len(parts) < 4 {
		logrus.Printf("格式不符合预期：%s", path)
		return nil, errors.New("格式不符合预期")
	}
	n := len(parts)
	msg := parts[n-1]
	dateTime := parts[n-2]
	dataType := parts[n-3]
	robotSn := parts[n-4]
	robotMsg := &RobotMsg{
		RobotSn:  robotSn,
		DataType: dataType,
		DateTime: dateTime,
		Msg:      msg,
	}
	return robotMsg, nil
}

// 获取磁盘使用情况
func (fh *FileHandler) diskUsage(path string) (DiskStat, error) {
	var fs unix.Statfs_t
	err := unix.Statfs(path, &fs)
	if err != nil {
		return DiskStat{}, err
	}

	total := fs.Blocks * uint64(fs.Bsize)
	free := fs.Bavail * uint64(fs.Bsize) // 使用 Bavail，为非特权用户的可用空间
	used := total - free

	usage := float64(used) / float64(total)

	return DiskStat{
		Total: total,
		Free:  free,
		Used:  used,
		Usage: usage,
	}, nil
}

// 获取目录下的所有文件
func (fh *FileHandler) getAllFiles(dirPath string) ([]*FileInfo, error) {
	var files []*FileInfo

	err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if !info.IsDir() {
			files = append(files, &FileInfo{
				Path:    path,
				ModTime: info.ModTime(),
			})
		} else if fh.isDirEmpty(path) {
			//检查目录是否为空
			logrus.Println("删除空目录：", path)
			if err := os.Remove(path); err != nil {
				logrus.Printf("删除目录失败：%s, 错误：%s\n", path, err)
			}
		}
		return nil
	})

	if err != nil {
		return nil, err
	}
	logrus.Printf("在目录下%s找到文件数量  %d:\n", dirPath, len(files))
	return files, nil
}

// IsFileExist 判断文件或文件夹是否存在
func (fh *FileHandler) IsFileExist(path string) (bool, error) {
	fileInfo, err := os.Stat(path)
	if err == nil {
		if fileInfo.Mode().IsDir() {
			// 如果是目录，返回错误
			return false, fmt.Errorf("%s is a directory", path)
		}
		return true, nil
	}

	if os.IsNotExist(err) {
		return false, nil
	}

	return false, err
}

// CreteFile 递归创建文件夹
func (fh *FileHandler) CreteFile(filePath string) error {
	if isExist, _ := fh.IsFileExist(filePath); isExist != true {
		if err := os.MkdirAll(filePath, os.ModePerm); err != nil {
			logrus.Printf("文件夹创建失败：%v\n", err)
			return err
		}
		logrus.Printf("文件夹创建成功：%s\n", filePath)
	} else {
		logrus.Printf("文件夹已经存在：%s\n", filePath)
	}
	return nil
}

// DeleteFile 删除对应的文件数据
func (fh *FileHandler) DeleteFile(str, dir string) bool {
	filePath := filepath.Join(source, str)
	isExist, _ := fh.IsFileExist(filePath)
	if isExist {
		if err := os.RemoveAll(filePath); err != nil {
			logrus.Printf("删除文件失败：%v\n", err)
			return false
		}
		logrus.Printf("删除成功：%s\n", filePath)

		// 判断目录是否为空，如果目录为空也删除
		parentDir := filepath.Join(source, dir)
		dirInfo, err := ioutil.ReadDir(parentDir)
		if err != nil {
			logrus.Printf("读取目录失败：%v\n", err)
			return false
		}
		if len(dirInfo) == 0 {
			if err := os.RemoveAll(parentDir); err != nil {
				logrus.Printf("删除空目录失败：%v\n", err)
				return false
			}
			logrus.Printf("删除成功，该文件目录为空：%s\n", parentDir)
		} else {
			logrus.Printf("该路径目录不为空：%s\n", parentDir)
		}
	}
	return true
}

func (fh *FileHandler) DoWork() {
	// 创建定时器，每隔一秒钟检测一次磁盘容量
	ticker := time.NewTicker(30 * time.Second)
	defer ticker.Stop() // 确保ticker被释放
	var sql string
	// 定义要检测的磁盘路径
	diskPath := "/"
	for {
		select {
		case <-ticker.C:
			// 获取磁盘状态信息
			diskStat, err := fh.diskUsage(diskPath)
			if err != nil {
				logrus.Printf("无法获取磁盘使用情况: %v\n", err)
				//os.Exit(1) // 发生错误时退出程序
			}
			logrus.Printf("磁盘路径: %s\n", diskPath)
			logrus.Printf("总容量: %d GB\n", diskStat.Total/1024/1024/1024)
			logrus.Printf("已使用: %d GB\n", diskStat.Used/1024/1024/1024)
			logrus.Printf("可用容量: %d GB\n", diskStat.Free/1024/1024/1024)
			logrus.Printf("使用率: %.2f%%\n", diskStat.Usage*100)
			logrus.Println("-----------------------------------------")

			// 检查磁盘使用情况是否超过阈值
			if diskStat.Usage > usageThreshold {
				// 打印磁盘使用情况
				logrus.Println("磁盘使用超过阈值，执行清理操作...")
				// 获取目录下所有文件
				files, err := fh.getAllFiles(source)
				if err != nil {
					fmt.Printf("无法获取目录下的文件列表: %v\n", err)
					//os.Exit(1) // 发生错误时退出程序
				}

				// 按照文件的修改时间进行排序（从旧到新）
				sort.Slice(files, func(i, j int) bool {
					return files[i].ModTime.Before(files[j].ModTime)
				})

				// 删除文件，直到磁盘使用情况低于阈值
				for _, file := range files {
					// 删除文件前检查权限
					info, err := fh.parseDetail(file.Path)
					if err != nil {
						logrus.Error("error: ", error(err))

					}
					logrus.Println("RobotSn:", info.RobotSn, "DataType: ", info.DataType, "DateTime: ", info.DateTime, "msg: ", info.Msg)
					if info.DataType == "RGB" {
						t, _ := time.Parse("20060102150405", info.DateTime)
						fmt.Println("DateTime: ", t.Format("2006-01-02 15:04:05"))
						sql = "DELETE from " + Ptv.DataBase.RGBTable + " where robotSn = " + "'" + info.RobotSn + "'" + " and dataType= " + "'" + info.DataType + "'" + " and dateTime=" + "'" + t.Format("2006-01-02 15:04:05") + "'" + " and msg = " + "'" + info.Msg + "'"
					}
					if info.DataType == "Depth" {
						t, _ := time.Parse("20060102150405", info.DateTime)
						fmt.Println("DateTime: ", t.Format("2006-01-02 15:04:05"))
						sql = "DELETE from " + Ptv.DataBase.DepthTable + " where robotSn = " + "'" + info.RobotSn + "'" + " and dataType= " + "'" + info.DataType + "'" + " and dateTime=" + "'" + t.Format("2006-01-02 15:04:05") + "'" + " and msg = " + "'" + info.Msg + "'"
					}
					if info.DataType == "Map" {
						t, _ := time.Parse("20060102150405", info.DateTime)
						fmt.Println("DateTime: ", t.Format("2006-01-02 15:04:05"))
						sql = "DELETE from " + Ptv.DataBase.MapTable + " where robotSn = " + "'" + info.RobotSn + "'" + " and dataType= " + "'" + info.DataType + "'" + " and dateTime=" + "'" + t.Format("2006-01-02 15:04:05") + "'" + " and msg = " + "'" + info.Msg + "'"
					}
					if info.DataType == "SIG" {
						t, _ := time.Parse("20060102150405", info.DateTime)
						fmt.Println("DateTime: ", t.Format("2006-01-02 15:04:05"))
						sql = "DELETE from " + Ptv.DataBase.RGBTable + " where robotSn = " + "'" + info.RobotSn + "'" + " and dataType= " + "'" + info.DataType + "'" + " and dateTime=" + "'" + t.Format("2006-01-02 15:04:05") + "'" + " and msg = " + "'" + info.Msg + "'"
					}
					db.DeleteDB(sql)
					if err := os.Remove(file.Path); err != nil {
						logrus.Printf("无法删除文件：%s, 错误：%v\n", file.Path, err)
						continue // 跳过不能删除的文件
					}
					// 更新磁盘使用情况
					diskStat, err = fh.diskUsage(diskPath)
					if err != nil {
						logrus.Printf("无法获取磁盘使用情况: %v\n", err)
						//获取不到不用做处理
						//os.Exit(1) // 发生错误时退出程序
					}
					// 检查磁盘使用情况是否低于阈值
					if diskStat.Usage <= usageThreshold {
						break
					}
				}

				logrus.Println("清理操作完成。")
			}
		}
	}
}
